﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Import;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Font = iTextSharp.text.Font;

namespace Web.Helpers.Documents.Scripts
{
    public class BRK : IScriptDocument
    {
        #region Constants
        public const int MainCharactersSize = 20;
        public const int AdditionalCharactersLoopsPerRow = 10;
        #endregion

        #region Properties
        public MemoryStream Stream { get; set; }
        #endregion

        public BRK(List<LoopInfo> loopsInfo, Dictionary<TimeCode, int> timeCodes, Dictionary<string, CharacterInfo> characters, string project)
        {
            try
            {
                this.Stream = Create( loopsInfo, timeCodes, characters, project );
            }
            catch (Exception)
            {
                throw;
            }
        }

        public void SaveToFile(string path, string filename)
        {
            filename = FileHelper.GetSafeFilename(path, filename);
            var fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write);
            this.Stream.Position = 0;
            this.Stream.WriteTo( fileStream );
                fileStream.Close();
            this.Stream.Close();
        }

        private static MemoryStream Create(List<LoopInfo> loopsInfo, Dictionary<TimeCode, int> timeCodes, Dictionary<string, CharacterInfo> characters, string project)
        {
            var ms = new MemoryStream();

            var pdfHelper = new PdfHelper();
            //var defaultCell = new PdfHelper.CellStyle() { Font = new PdfHelper.CellStyle.CellFont() { Size = 10f } };
            //pdfHelper.SetDefaultCell( defaultCell );

            var mainCharacters = characters.OrderByDescending(x => x.Value.Loops).Take(MainCharactersSize).ToDictionary(x => x.Key, x => x.Value);
            var additionalCharacters = characters.Except( mainCharacters ).OrderByDescending(x => x.Value.Loops).ToDictionary(x => x.Key, x => x.Value);

            //using (Document doc = new Document(PageSize.LETTER))
            //{
            //    using (PdfWriter w = PdfWriter.GetInstance(doc, fs))
            //    {
            //    }
            //}

            var doc = new Document(PageSize.LEGAL, 25, 25, 40, 40);
    
            var pdfWriter = PdfWriter.GetInstance( doc, ms );

            //var PageEventHandler = new BrkPageEvent();
            //    pdfWriter.PageEvent = PageEventHandler;

            //// Define the page header
            //PageEventHandler.Title = "HOLAA";
            //PageEventHandler.HeaderFont = FontFactory.GetFont(BaseFont.COURIER_BOLD, 10, Font.BOLD);
            //PageEventHandler.HeaderLeft = "Group";
            //PageEventHandler.HeaderRight = "1";

            doc.Open();

            var pageNumber = pdfWriter.PageNumber;

            var page = 1;
            var loopsPerPage = 50;
            var loopsTotal = loopsInfo.Count;
            for (var loop = 0; loop < loopsTotal; loop = loop + loopsPerPage)
            {
                if ( page > 1 )
                    doc.NewPage();
                page++;

                //SetPageHeader(pdfWriter, doc, String.Format("{0}", keyword), String.Format("HOJA BREAK - {0}", pdfWriter.PageNumber) );
                SetPageHeader(pdfWriter, doc, String.Empty, String.Format("HOJA BREAK - {0}", pdfWriter.PageNumber) );

                var tblMain = new PdfPTable( mainCharacters.Count + 3 ); //3 = Loop, Pagina, TimeCode

                SetMainCharactersTableWidth(tblMain, mainCharacters.Count);

                CreateHeaderTable(pdfHelper, tblMain, mainCharacters);
                CreateLoopContentPage(pdfHelper, tblMain, loopsInfo, timeCodes, mainCharacters, loop, loopsPerPage);
                
                doc.Add( tblMain );
            }

            #region Additional Characters
            page = 1;
            if (characters.Count > MainCharactersSize)
            {
                //if ( page > 1 )
                    doc.NewPage();
                page++;

                //SetPageHeader(pdfWriter, doc, String.Format("{0}", keyword), String.Format("HOJA BREAK - {0}", pdfWriter.PageNumber) );
                SetPageHeader(pdfWriter, doc, String.Empty, String.Format("HOJA BREAK - {0}", pdfWriter.PageNumber) );

                var tblAdditional = new PdfPTable( 3 + AdditionalCharactersLoopsPerRow ); //1=AppearanceOrder, 2=CharacterName, 3="" + 10 cells

                SetAdditionalCharactersTableWidth(tblAdditional, AdditionalCharactersLoopsPerRow);

                //doc.NewPage();
                CreateAdditionalCharactersPage(pdfHelper, tblAdditional, loopsInfo, additionalCharacters, MainCharactersSize, AdditionalCharactersLoopsPerRow);

                doc.Add( tblAdditional );
            }
            #endregion

            //doc.AddAuthor("EL AUTHOR");
            //doc.AddCreator("EL CREATOR");
            //doc.AddHeader("EL HEADER", "??");
            //doc.AddSubject("EL SUBJECT");
            //doc.AddTitle("EL TITTLE");

            pdfWriter.Flush();
            pdfWriter.CloseStream = false;

            doc.Close();

            //cb = null;
            pdfWriter = null;
            doc = null;

            ms.Position = 0;

            return ms;
        }

        public class BrkPageEvent : PdfPageEventHelper
        {
            PdfContentByte cb;
            //PdfTemplate template;
            BaseFont bf = null;
            
            DateTime PrintTime = DateTime.Now;

            #region Properties
            private string _Title;
            public string Title
            {
                get { return _Title; }
                set { _Title = value; }
            }
            private string _HeaderLeft;
            public string HeaderLeft
            {
                get { return _HeaderLeft; }
                set { _HeaderLeft = value; }
            }
            private string _HeaderRight;
            public string HeaderRight
            {
                get { return _HeaderRight; }
                set { _HeaderRight = value; }
            }
            private Font _HeaderFont;
            public Font HeaderFont
            {
                get { return _HeaderFont; }
                set { _HeaderFont = value; }
            }
            private Font _FooterFont;
            public Font FooterFont
            {
                get { return _FooterFont; }
                set { _FooterFont = value; }
            }
            #endregion
            
            public override void OnOpenDocument(PdfWriter writer, Document document)
            {
                try
                {
                    PrintTime = DateTime.Now;
                    bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
                    cb = writer.DirectContent;
                    //template = cb.CreateTemplate(50, 50);
                }
                catch (DocumentException)
                {
                }
                catch (IOException)
                {
                }
            }
            public override void OnStartPage(PdfWriter writer, Document document)
            {
                base.OnStartPage(writer, document);

                var pageNumber = writer.PageNumber;
                var text = String.Format("HOJA BREAK - {0}", pageNumber);
                //var len = bf.GetWidthPoint(text, 8);
                iTextSharp.text.Rectangle pageSize = document.PageSize;
                //cb.SetRGBColorFill(100, 100, 100);
                //cb.BeginText();
                //cb.SetFontAndSize(bf, 8);
                //cb.SetTextMatrix(pageSize.GetLeft(40), pageSize.GetBottom(30));
                //cb.ShowText(text);
                //cb.EndText();
                //cb.AddTemplate(template, pageSize.GetLeft(40) + len, pageSize.GetBottom(30));
                
                cb.BeginText();
                cb.SetFontAndSize(bf, 8);
                cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT, text, pageSize.GetRight(40), pageSize.GetTop(20), 0);
                cb.EndText();

                //iTextSharp.text.Rectangle pageSize = document.PageSize;
                //if (Title != string.Empty)
                //{
                //    cb.BeginText();
                //    cb.SetFontAndSize(bf, 15);
                //    cb.SetRGBColorFill(50, 50, 200);
                //    cb.SetTextMatrix(pageSize.GetLeft(40), pageSize.GetTop(40));
                //    cb.ShowText(Title);
                //    cb.EndText();
                //}
                //if (HeaderLeft + HeaderRight != string.Empty)
                //{
                //    var HeaderTable = new PdfPTable(2);
                //        HeaderTable.DefaultCell.VerticalAlignment = Element.ALIGN_MIDDLE;
                //        HeaderTable.TotalWidth = pageSize.Width - 80;
                //        HeaderTable.SetWidthPercentage(new float[] { 45, 45 }, pageSize);

                //    var HeaderLeftCell = new PdfPCell(new Phrase(8, HeaderLeft, HeaderFont));
                //        HeaderLeftCell.Padding = 5;
                //        HeaderLeftCell.PaddingBottom = 8;
                //        HeaderLeftCell.BorderWidthRight = 0;
                //        HeaderTable.AddCell(HeaderLeftCell);

                //    var HeaderRightCell = new PdfPCell(new Phrase(8, HeaderRight, HeaderFont));
                //        HeaderRightCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
                //        HeaderRightCell.Padding = 5;
                //        HeaderRightCell.PaddingBottom = 8;
                //        HeaderRightCell.BorderWidthLeft = 0;
                //        HeaderTable.AddCell(HeaderRightCell);

                //    cb.SetRGBColorFill(0, 0, 0);
                //    HeaderTable.WriteSelectedRows(0, -1, pageSize.GetLeft(40), pageSize.GetTop(50), cb);
                //}
            }
            public override void OnEndPage(PdfWriter writer, Document document)
            {
                base.OnEndPage(writer, document);

                var canvas = writer.DirectContent;

                canvas.BeginText();
                canvas.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 8);
                canvas.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "Para uso exclusivo de Caja de Ruidos", document.PageSize.GetLeft(40), document.PageSize.GetBottom(25), 0);
                canvas.EndText();   
            }
            public override void OnCloseDocument(PdfWriter writer, Document document)
            {
                base.OnCloseDocument(writer, document);

                //template.BeginText();
                //template.SetFontAndSize(bf, 8);
                //template.SetTextMatrix(0, 0);
                //template.ShowText("" + (writer.PageNumber - 1));
                //template.EndText();
            }
        }

        private static void SetPageHeader(PdfWriter writer, Document document, string leftText, string rightText)
        {
            //var cb = new PdfContentByte(pdfWriter);
            var bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
            var cb = writer.DirectContent;

            iTextSharp.text.Rectangle pageSize = document.PageSize;

            ////KEYWORD
            //cb.BeginText();
            //cb.SetFontAndSize(bf, 8);
            //cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, leftText, pageSize.GetLeft(40), pageSize.GetTop(20), 0);
            //cb.EndText();       

            //PAGE NUMBER
            cb.BeginText();
            cb.SetFontAndSize(bf, 8);
            cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT, rightText, pageSize.GetRight(40), pageSize.GetTop(20), 0);
            cb.EndText();            
        }

        private static void SetMainCharactersTableWidth(PdfPTable table, int mainCharactersCount)
        {
            var cellWidths = new List<float>(); //new float[5] { 25, [15 * mainCharactersCount], 20, 45 };
                cellWidths.Add( 25f );
            for (var i = 0; i < mainCharactersCount; i++)
            {
                cellWidths.Add( 15f );
            }
                cellWidths.Add( 20f );
                cellWidths.Add( 45f );

            table.SetWidths( cellWidths.ToArray() ); //table.SetTotalWidth(cellWidths.ToArray());
            table.WidthPercentage = 100; //table.TotalWidth = cellWidths.Sum();
            //table.LockedWidth = true;
        }

        private static void SetAdditionalCharactersTableWidth(PdfPTable table, int additionalCharactersLoopsPerRow)
        {
            var cellWidths = new List<float>();
                cellWidths.Add( 20f );
                cellWidths.Add( 50f );
                cellWidths.Add( 20f );
                for (var i = 0; i < additionalCharactersLoopsPerRow; i++)
                {
                    cellWidths.Add( 20f );
                }
                table.TotalWidth = cellWidths.Sum();
                //table.LockedWidth = true;
                table.SetWidths( cellWidths.ToArray() );
                //table.SetTotalWidth(cellWidths.ToArray());            
        }

        private static void CreateHeaderTable(PdfHelper pdfHelper, PdfPTable table, Dictionary<string, CharacterInfo> characters)
        {
            var headerColTextCellStyle = new PdfHelper.CellStyle()
            {
                Font = new PdfHelper.CellStyle.CellFont() { Size = 13f },
                Span = new PdfHelper.CellStyle.CellSpan() {Rows = 2},
                Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 20f, Top = 20f }
            };

            var headerColNumberCellStyle = new PdfHelper.CellStyle()
            {
                Font = new PdfHelper.CellStyle.CellFont() { Size = 10f },
                Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5f, Top = 5f }
            };

            var headerCharacterCellStyle = new PdfHelper.CellStyle()
            {
                Rotation = PdfHelper.CellStyle.CellRotation.BottomToTop,                
                Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left, Vertical = PdfHelper.CellStyle.CellAlignment.VerticalAlignment.Middle },
                Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 10 }
            };

            pdfHelper.AddCell(table, GetTextIntoLines("LOOP"), headerColTextCellStyle );

            for(var i=1; i < characters.Count +1; i++)
            {
                pdfHelper.AddCell(table, i.ToString(), headerColNumberCellStyle );
            }

            pdfHelper.AddCell(table, GetTextIntoLines("PÁGINA"), headerColTextCellStyle );
            pdfHelper.AddCell(table, GetTextIntoLines("TIME CODE"), headerColTextCellStyle );

            foreach (var character in characters)
            {
                pdfHelper.AddCell(table, character.Key, headerCharacterCellStyle);
            }

        }

        private static void CreateLoopContentPage(PdfHelper pdfHelper, PdfPTable table, List<LoopInfo> loopsInfo, Dictionary<TimeCode, int> timeCodes, Dictionary<string, CharacterInfo> characters, int startingRow, int loopsPerPage)
        {
            try
            {
                var rowCellStyle = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10 },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 3f, Top = 2f }
                };

                var arrCharacters = characters.ToArray();
                for (var rows = 0; rows < loopsPerPage; rows++)
                {
                    var hasLoops = loopsInfo.Count > (rows + startingRow);

                    pdfHelper.AddCell(table, hasLoops ? (startingRow + rows + 1).ToString() :  String.Empty, rowCellStyle);
                    for(var i=0; i < arrCharacters.Length; i++)
                    {
                        var characterName = String.Empty;
                        if ( hasLoops )
                        {
                            if (loopsInfo[rows + startingRow].CharacterNames.Contains(arrCharacters[i].Key))
                            {
                                characterName = arrCharacters[i].Key.Length > 2
                                    ? arrCharacters[i].Key.Substring(0, 2)
                                    : arrCharacters[i].Key;
                            }
                        }
                        pdfHelper.AddCell(table, characterName, new PdfHelper.CellStyle() { Font = new PdfHelper.CellStyle.CellFont() { Size = 9 } });
                    }

                    var pageNumber = 0;
                    if ( hasLoops )
                    {
                        var timeCode = loopsInfo[rows + startingRow].TimeCode;
                        pageNumber = timeCodes.First(x => TimeCode.AreEqual(x.Key, timeCode)).Value;
                    }
                    pdfHelper.AddCell(table, hasLoops ? pageNumber.ToString() : String.Empty, rowCellStyle);

                    pdfHelper.AddCell(table, hasLoops ? loopsInfo[rows + startingRow].TimeCode.ToString() : String.Empty, rowCellStyle);
                }   
            }
            catch (Exception)
            {
                throw;
            }         
        }

        private static void CreateAdditionalCharactersPage(PdfHelper pdfHelper, PdfPTable table, List<LoopInfo> loopsInfo, Dictionary<string, CharacterInfo> characters, int mainCharactersSize, int additionalCharactersLoopsPerRow)
        {
            var headerCellStyle = new PdfHelper.CellStyle()
            {
                Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                Font = new PdfHelper.CellStyle.CellFont() { Size = 14, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                Span = new PdfHelper.CellStyle.CellSpan() {Cols = 13}
            };

            var borderlessBoldCellStyle = new PdfHelper.CellStyle()
            {
                Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left }
            };

            var borderlessCellStyle = new PdfHelper.CellStyle()
            {
                Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left }
            };

            pdfHelper.AddCell(table, "PERSONAJES ADICIONALES", headerCellStyle);
            pdfHelper.AddCells(table, new string[13], borderlessCellStyle);
            
            var arrCharacters = characters.ToArray();
            for(var i=0; i < arrCharacters.Length; i++)
            {
                var characterName = arrCharacters[i].Key;

                pdfHelper.AddCell(table, String.Format("({0})", (i + mainCharactersSize +1)), borderlessBoldCellStyle );
                pdfHelper.AddCell(table, characterName, borderlessCellStyle);
                pdfHelper.AddCell(table, String.Empty, borderlessCellStyle);

                var characterLoops = loopsInfo.Where(x => x.CharacterNames.Contains(characterName)).OrderBy(x => x.Number).ToList();
                var rows = Math.Ceiling( characterLoops.Count() / 10f );
                for (var k = 0; k < rows; k++)
                {
                    for (var j = 0; j < additionalCharactersLoopsPerRow; j++)
                    {
                        pdfHelper.AddCell(table, characterLoops.Count() > j ? characterLoops[j].Number.ToString() : String.Empty );
                    }
                }

                pdfHelper.AddCells(table, new string[13], borderlessCellStyle);
            }
        }

        private static string GetTextIntoLines(string text)
        {
            var words = String.Empty;
            return text.ToCharArray().Aggregate(words, (current, ch) => current + (ch + Environment.NewLine));
        }
    }
}